/*
 * Copyright (C) 2020 The zfoo Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and limitations under the License.
 */

package org.ricks.ioc.scheduler;

import org.ricks.ioc.BeanAnalysisProcessor;
import org.ricks.ioc.HotfixManager;
import org.ricks.ioc.utils.*;

import java.lang.reflect.Modifier;

/**
 * 这是一个后置处理器，在boot项目中注册EventContext时，会import导入EventRegisterProcessor这个组件，这是一个后置处理器，
 * 断点发现 在AbstractAutowireCapableBeanFactory或调用getBeanPostProcessors，这样子每一个Bean创建后都会走postProcessAfterInitialization这个方法
 *
 * @author godotg
 */
public class SchedulerRegisterProcessor implements BeanAnalysisProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean) throws IocException {
        // 优先使用热更后的类
        Class<?> actualClass = HotfixManager.getHotfixClass(bean.getClass().getName());
        if (actualClass != null) {
            try {
                // 创建热更后的实例并复制字段值
                Object hotfixBean = actualClass.newInstance();
                copyFieldValues(bean, hotfixBean);
                bean = hotfixBean;
            } catch (Exception e) {
                Logger.error("创建热更Action实例失败", e);
            }
        }
        var clazz = bean.getClass();
        var methods = ReflectUtils.getMethodsByAnnoInPOJOClass(clazz, Scheduled.class);
        if (ArrayUtils.isEmpty(methods)) {
            return bean;
        }

        if (!ReflectUtils.isPojoClass(clazz)) {
            Logger.warn(StringUtils.format("The message registration class [{}] is not a POJO class, and the parent class " +
                    "will not be " +
                    "scanned", clazz));
        }

        try {
            for (var method : methods) {
                var schedulerMethod = method.getAnnotation(Scheduled.class);

                var paramClazzs = method.getParameterTypes();
                if (paramClazzs.length >= 1) {
                    throw new IllegalArgumentException(StringUtils.format("[class:{}] [method:{}] can not have any parameters", bean.getClass(), method.getName()));
                }

                var methodName = method.getName();

                if (!Modifier.isPublic(method.getModifiers())) {
                    throw new IllegalArgumentException(StringUtils.format("[class:{}] [method:{}] must use 'public' as modifier!", bean.getClass().getName(), methodName));
                }

                if (Modifier.isStatic(method.getModifiers())) {
                    throw new IllegalArgumentException(StringUtils.format("[class:{}] [method:{}] can not use 'static' as modifier!", bean.getClass().getName(), methodName));
                }

//                if (!methodName.startsWith("cron")) {
//                    throw new IllegalArgumentException(StringUtils.format("[class:{}] [method:{}] must start with 'cron' as method name!"
//                            , bean.getClass().getName(), methodName));
//                }

                if(!StringUtils.isBlank(schedulerMethod.cron())) {
                    var scheduler = SchedulerDefinition.valueOf(schedulerMethod.cron(), bean, method);
                    SchedulerBus.registerTask(scheduler);
                }
                if(schedulerMethod.initialDelay() >=0 && schedulerMethod.fixedRate() > 0) {
                    var scheduler = SchedulerDefinition.valueOf(schedulerMethod.initialDelay(), schedulerMethod.fixedRate(), bean, method);
                    SchedulerBus.registerTask(scheduler);
                }
            }
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }

        return bean;
    }

}
